package java7;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import java.util.concurrent.RecursiveTask;

public class J7 {
    public static void main(String[] args) {
        int ap = Runtime.getRuntime().availableProcessors();//得到逻辑核数
        //内容补充，逻辑物理核其实还是存在并发竞争关系，在我本地是2核四线程，如果核1是映射的是线程1，2 核2是线程3，4
        //那么线程1和线程2在同时操作同一个对象的时候就存在竞争关系（而且线程1和线程2同一时刻也只能只有一个线程执行，
        //因为它们位于一个核里面），
        //也就存在并发问题，所以要注意多线程的问题，对于多线程来说，决定多线程的效率取决于2个因素
        //1是否是IO密集型  2是否是计算密集型  如果是IO密集型的话线程越多越好，计算密集型的线程越少越好
        //在《Java虚拟机并发编程》里面有个大概的线程数算法：
        //合理的线程数=逻辑物理核数/(1-0.0)
        //线程数越多 对于线程上下文切换花费的时间会越来越长，所以合理的线程数是有必要的
        ForkJoinPool pool = new ForkJoinPool(ap);
        MyTask task = new MyTask(1);
        Future<Integer> result = pool.submit(task);
        try {
            int rt = result.get();
            System.out.println(rt);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
        pool.shutdown();
    }

    /**
     * RecursiveTask(有返回值) 和 RecursiveAction(无返回值)
     * ForkJoinPool 采用工作窃取方法
     * 1.把任务放在多个队列  给每个队列分配一个线程  通常会使用双端队列，被窃取任务线程永远从双端队列的头部拿任务执行，
     * 而窃取任务的线程永远从双端队列的尾部拿任务执行。
     * 当然这也存在一个问题  如果队列只存在一个任务也会产生竞争
     *
     * @author user
     */
    static class MyTask extends RecursiveTask<Integer> {
        /**
         *
         */
        private static final long serialVersionUID = 2860748473225804796L;
        int i;

        public MyTask(int i) {
            this.i = i;
        }

        @Override
        protected Integer compute() {
            if (i > 2) {
                return i * i;
            }
            MyTask task = new MyTask(i + 1);
            task.fork();

            return i * i + task.join();
        }

    }

}
